﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using SkinnedModel;
using Microsoft.Xna.Framework.Media;
using System;

namespace whereIsTheDonutGame
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Player : SuperPlayer
    {
        bool blocked;
        float oldState;
        float speed = 0.7f;
        public short life;
        float t = 0.5f;

        bool inAir = false;
        bool jumped = false;
        float veloY = 0, gravity = 0.2f;
        float mouseSpeed = 0.005f;
        SoundEffect soundEffect;
        SoundEffect moveblock;
        SoundEffectInstance instance;

        

        //donutGame game;
        public Player(donutGame game)
            : base(game)
        {
            oldState = Mouse.GetState().X;
            soundEffect = game.Content.Load<SoundEffect>("Sounds/jamjamjam");
            moveblock = game.Content.Load<SoundEffect>("Sounds/moveblock");
            instance = moveblock.CreateInstance();
            this.game = game;
            life = 3;
            position = new Vector3(150, game.terrain.Height[15,15] + 3, -150);
        }

        public override void Update(GameTime gameTime)
        {


            KeyboardState state = Keyboard.GetState();
            movement = Vector3.Zero;
            blocked = false;
            //Jump
            if (state.IsKeyDown(Keys.Space) && !inAir)
            {
                veloY = 2.5f;
                jumped = true;
            }

            jump();

            //WASD
            if (state.IsKeyDown(Keys.W))
            {
                movement.Z = -speed;
            }
            if (state.IsKeyDown(Keys.S))
            {
                movement.Z = speed;
            }
            if (state.IsKeyDown(Keys.A))
            {
                movement.X = -speed;
            }
            if (state.IsKeyDown(Keys.D))
            {
                movement.X = speed;
            }

            //Rotation
            if (state.IsKeyDown(Keys.Right))
            {
                rotate(-0.05f);
            }
            if (state.IsKeyDown(Keys.Left))
            {
                rotate(0.05f);
            }

            rotate(mouseSpeed * (oldState - Mouse.GetState().X));
            Mouse.SetPosition(500, 500);
            oldState = Mouse.GetState().X;


            Matrix facingMatrix = Matrix.CreateRotationY(rotation);
            Vector3 velocity = Vector3.Transform(movement, facingMatrix);
            velocity *= PlayerVelocity; // atm redundant, da speed auch geschwindigkeit festlegt.

            Vector3 newPosition = position + velocity;
            //FIRST CHECK IF ON TERRAIN!
            BoundingBox newBoundingBox = Stuff.CalculateBoundingBox(player, Matrix.CreateTranslation(newPosition));
            if (game.terrain.isValidPosition(newPosition))
            {

                if (!inAir)
                {
                    newPosition.Y = game.terrain.Height[(int)newPosition.X, (int)-newPosition.Z] + 5;
                }

                if (game.terrain.Height[(int)newPosition.X, (int)-newPosition.Z] > game.terrain.Height[(int)position.X, (int)-position.Z] + 1)
                {
                    blocked = true;
                }

                foreach (Solid s in game.cspawn.solids)
                {
                    foreach (BoundingBox box in s.getBoundingBoxes())
                    {
                        if (newBoundingBox.Intersects(box))
                            blocked = true;
                    }
                }
                if (!inAir)
                {
                    foreach (MovableBox m in game.cspawn.boxes)
                    {
                        if (new BoundingBox(new Vector3(newPosition.X - 5, newPosition.Y - 5, newPosition.Z - 5), new Vector3(newPosition.X + 5, newPosition.Y + 5, newPosition.Z + 5)).Intersects(m.boundingBox)) // check if player collides with box and then in wich direction box has to move
                        {
                            instance.Play();

                            if (this.Position.X < m.Position.X - 1.5 && (m.Position.Z + t > this.Position.Z || m.Position.Z - t < this.Position.Z))
                            {
                                if (m.isValidPosition(new Vector3(m.Position.X + speed, 1, m.Position.Z))) //check if new box position is valid
                                {
                                    m.Position = new Vector3(m.Position.X + speed, game.terrain.Height[(int)(m.Position.X + speed), (int)-m.Position.Z] + 3, m.Position.Z); //move Box when valid
                                }
                                else
                                {
                                    blocked = true;  //dont move anyway
                                }
                            }
                            else if (this.Position.X > m.Position.X + 1.5 && (m.Position.Z + t > this.Position.Z || m.Position.Z - t < this.Position.Z))
                            {
                                if (m.isValidPosition(new Vector3(m.Position.X - speed, 1, m.Position.Z)))
                                {
                                    m.Position = new Vector3(m.Position.X - speed, game.terrain.Height[(int)(m.Position.X - speed), (int)-m.Position.Z] + 3, m.Position.Z);
                                }
                                else
                                {
                                    blocked = true;
                                }
                            }
                            else if (this.Position.Z < m.Position.Z && (m.Position.X + t > this.Position.X || m.Position.X - t < this.Position.X))
                            {
                                if (m.isValidPosition(new Vector3(m.Position.X, 1, m.Position.Z + speed)))
                                {
                                    m.Position = new Vector3(m.Position.X, game.terrain.Height[(int)m.Position.X, (int)-(m.Position.Z + speed)] + 3, m.Position.Z + speed);
                                }
                                else
                                {
                                    blocked = true;
                                }
                            }
                            else if (this.Position.Z > m.Position.Z && (m.Position.X + t > this.Position.X || m.Position.X - t < this.Position.X))
                            {
                                if (m.isValidPosition(new Vector3(m.Position.X, 1, m.Position.Z - speed)))
                                {
                                    m.Position = new Vector3(m.Position.X, game.terrain.Height[(int)m.Position.X, (int)-(m.Position.Z - speed)] + 3, m.Position.Z - speed);
                                }
                                else
                                {
                                    blocked = true;
                                }
                            }
                            else
                            {
                                blocked = true;
                            }
                        }
                    }

                }
            }
            else
            {
                blocked = true;
            }


            if (!blocked)
                position = newPosition;

            UpdateBoundingBox(); //calcs new boundingbox for new playerposition

            checkDonutCollision(); // check for collision with donuts


            base.Update(gameTime);
        }

        private void updateMatrices()
        {

        }

        private void checkDonutCollision()
        {

            foreach (Donut d in game.spawn.donuts)
            {
                if (this.bbox.Intersects(d.BoundingBox) && d.recieved == false)
                {
                    d.recieved = true;
                    game.hud.counter++;
                    soundEffect.Play();
                }
            }
        }

        private void checkWorldCollision()
        {

        }

        private void heightcheck()
        {


        }
        public void jump()
        {
            if (jumped)
            {
             
                  movement.Y += veloY;
                inAir = true;
                
                veloY -= gravity;
                if (position.Y <= game.terrain.height[(int)position.X, (int)-position.Z] + 4.99f)
                {
                    jumped = false;
                    inAir = false;
                }
            }

        }

        public override void UpdateBoundingBox()
        {
            bbox = Stuff.CalculateBoundingBox(player, Matrix.CreateTranslation(new Vector3(Position.X + 2.5f, Position.Y + 4, Position.Z + 2.5f)));
        }


        // TODO: CHECK FOR BOXES LEAVING WORLD -> ARRAY OUT OF BOUNDS -> chck if >511 || < 0
        private void checkBoxCollision()
        {

        }


        protected override void LoadContent()
        {
            player = this.Game.Content.Load<Model>("HomerSimpson");


        }

        public override void Draw(Microsoft.Xna.Framework.GameTime gameTime)
        {
            //Matrix[] bones = animationPlayer.GetSkinTransforms();

            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            foreach (ModelMesh mesh in player.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.View = camera.ViewMatrix;

                    effect.World = Matrix.CreateRotationY(rotation) * Matrix.CreateScale(0.5f) * Matrix.CreateTranslation(Position) * Matrix.CreateTranslation(new Vector3(0, 2, 0));

                    effect.Projection = camera.ProjectionMatrix;

                }
                mesh.Draw();
            }
            base.Draw(gameTime);

        }
    }
}